var production=true;
function initAll(){
	var canvas=document.getElementById('canvas');
	var context2D=canvas.getContext('2d');	
	$("#canvas").click(function(e){
		alert(e.pageX+"/"+e.pageY);
		}); 
	context2D.fillStyle="#eeeeee";		
	context2D.fillRect(0,0,500,500);
	//testBinding();
	//testText();
	//testCalculation();
	//testToggle();
	out("finished");
	}
function testCalculation(){
	out("<hr/>testCalculation");
	var tFahrenheit = new It().value(0.0);
	var tCelsius = new It().value(0.0);
	var c=new Calculation(tFahrenheit, tCelsius);
	c.calculateFirst=function() {
		return tCelsius.value * 9.0 / 5.0 + 32.0;
	    };
	c.calculateSecond=function() {
		return (tFahrenheit.value - 32) * 5.0 / 9.0;
	    };
	out("let tFahrenheit=100");
	tFahrenheit.value(100.0);
	out("now tFahrenheit: " + tFahrenheit.value() + ", tCelsius: " + tCelsius.value());
	out("let tCelsius=100");
	tCelsius.value(100.0);
	out("now tFahrenheit: " + tFahrenheit.value() + ", tCelsius: " + tCelsius.value());
	out("done<hr/>");
	}	
function testText(){
	out("<hr/>testText");
	//var a = new Text().value("A").append("!");
	//var b = new Text().value("B").append(a);
	//out(a.value()+"/"+b.value());
	//out(a);
	out("done<hr/>");
	}	
function testToggle(){
	out("<hr/>testToggle");
	var t=new Text().value("Qwerty");
	var t2=new Text().value("w");
	//out("start t: "+t.value()+", t2: "+t2.value());
	//var b=new Toggle().equals(t2,"w1fg");
	var tgl=new Toggle().equals(t,t2);
	//out("end t: "+t.value()+", tgl: "+tgl.value()+", t2: "+t2.value());
	/*var a=new Toggle().value(true);
	var b=new Toggle().value(true);
	out(a.and(b).value());*/
	//dump(a);
	//var a = new It().value("A");
	out(tgl.value());
	t2.value("Qwerty");
	out(tgl.value());
	out("done<hr/>");
	}	
function testBinding(){	
	out("<hr/>testBinding");
	var a = new It().value("A");
	var b = new It().value("B");
	var c = new It().value("C");
	a.afterChange=function(){out("!a.changed to "+this.value());};
	b.afterChange=function(){out("!b.changed to "+this.value());};
	c.afterChange=function(){out("!c.changed to "+this.value());};
	out("a: " + a.value() + ", b: " + b.value() + ", c: " + c.value());
	out("#bind variables");
	a.bind(b);
	b.bind(c);
	c.bind(a);
	out("a: " + a.value() + ", b: " + b.value() + ", c: " + c.value());
	out("#let a=D");
	a.value("D");
	out("a: " + a.value() + ", b: " + b.value() + ", c: " + c.value());
	out("#a unbind b");
	a.unbind(b);
	out("#let a=E");
	a.value("E");
	out("a: " + a.value() + ", b: " + b.value() + ", c: " + c.value());
	out("#let b=F");
	b.value("F");
	out("a: " + a.value() + ", b: " + b.value() + ", c: " + c.value());
	out("#a unbind c");
	a.unbind(c);
	out("#let a=G");
	a.value("G");
	out("a: " + a.value() + ", b: " + b.value() + ", c: " + c.value());
	out("#let b=H");
	b.value("H");
	out("a: " + a.value() + ", b: " + b.value() + ", c: " + c.value());
	out("done<hr/>");
	}
function out(msg){
	document.getElementById('out').innerHTML=document.getElementById('out').innerHTML+"\n"+new Date()+": "+msg;
	}	
function debug(msg){
	if(!production)out("debug: "+msg);
	}
function dump(object){
	var r="";
	for(var i in object)r=r+"\n"+i+": "+object[i];
	out (object.prototype+": "+r);
	}	
function arrayContains(it,ary){
	var exists;
	exists=false;
	for(var i=0;i<ary.length; i++) {
		if(ary[i]==it){
			exists=true;
			break;
			}						
		}
	return exists;
	}
function removeFromArray(it,ary){
	for(var i=0;i<ary.length; i++) {
		if(ary[i]==it){
			ary.splice(i,1);
			break;
			}
		}
	}	
function It(){
	this.binded=[];
	this._=undefined;
	this.afterChange=undefined;
	this.value=function(newValue){		
		if(newValue!=undefined){
			var cache=[];
			this.setForEachBindedItem(newValue,cache);
			return this;
			}
		else return this._;
		};
	this.bind=function(it){
		if(!arrayContains(it,this.binded))this.binded.push(it);
		if(!arrayContains(this,it.binded))it.binded.push(this);
		this.value(it.value());		
		return this;
		};
	this.unbind=function(it){
		removeFromArray(it,this.binded);
		removeFromArray(this,it.binded);
		};
	this.doAfterChange=function(){
		if (this.afterChange!=undefined)this.afterChange();
		}
	this.setForEachBindedItem=function(newValue,cache){		
		if(this._!=newValue){
			//out("["+this._+"]=["+newValue+"]");
			this._=newValue;
			//adjust();
			cache.push(this);
			for(var i=0;i<this.binded.length;i++){
				//out("i - "+this.binded[i].value());
				if(!arrayContains(this.binded[i],cache)){
					this.binded[i].setForEachBindedItem(newValue,cache);
					}
				}
			cache.pop();
			this.doAfterChange();
			}
		};
	}
function Text(){
	this.binded=[];
	this._="";
	this.append=function(it){
		if(it instanceof Text)return this.appendText(it);
		else return this.appendString(it);
		};
	this.appendText=function(text){
		out("appendText");
		var me=this;
		var retvalue=new Text().value(me.value()+text.value());
		new Text().bind(text).afterChange=function(){retvalue.value(me.value()+text.value());};
		return retvalue;
		};
	this.appendString=function(){
		out("appendString");
		return this;
		};
	}	
Text.prototype=new It(); 	
function Amount(){
	this.binded=[];
	this._=0;
	}
Amount.prototype=new It();
function Toggle(){
	this.binded=[];
	this._=false;
	this.and=function(toggle){
		var me=this;
		var retvalue=new Toggle();
		var afterChange=function(){retvalue.value(me.value() && toggle.value());};
		afterChange();
		new Toggle().bind(toggle).afterChange=afterChange();
		return retvalue;
		};
	this.or=function(toggle){
		var me=this;
		var retvalue=new Toggle();
		var afterChange=function(){retvalue.value(me.value() || toggle.value());};
		afterChange();
		new Toggle().bind(toggle).afterChange=afterChange();
		return retvalue;
		};
	this.like=function(v1,v2){
		if(v1 instanceof Text){
			if(v2 instanceof Text)return this.likeTextText(v1,v2) 
			else return this.likeTextString(v1,v2)
			}
		else return this.likeStringText(v1,v2)
		}
	this.likeTextText=function(a,b){
		var retvalue=new Toggle();
		var afterChange=function(){retvalue.value(a.value().indexOf(b.value())>-1);};
		afterChange();
		new Text().bind(a).afterChange=afterChange;
		new Text().bind(b).afterChange=afterChange;		
		return retvalue;
		}
	this.likeStringText=function(a,t){
		return this.like(new Text().value(a),b);
		}
	this.likeTextString=function(a,b){
		return this.like(a,new Text().value(b));
		}
	this.equals=function(v1,v2){
		if(v1 instanceof Text && v2 instanceof Text)return this.equalsExact(v1,v2) 
		if(v1 instanceof Text && v2 instanceof String)return this.equalsTextString(v1,v2) 
		if(v1 instanceof String && v2 instanceof Text)return this.equalsStringText(v1,v2) 
		if(v1 instanceof Amount && v2 instanceof Amount)return this.equalsExact(v1,v2) 
		if(v1 instanceof Amount && v2 instanceof Number)return this.equalsAmountNumber(v1,v2) 
		if(v1 instanceof Number && v2 instanceof Amount)return this.equalsNumberAmount(v1,v2) 
		return this;
		}
	this.equalsExact=function(a,b){
		var retvalue=new Toggle();
		var afterChange=function(){retvalue.value(a.value()==b.value());};
		afterChange();
		new Text().bind(a).afterChange=afterChange;
		new Text().bind(b).afterChange=afterChange;		
		return retvalue;
		}
	this.equalsStringText=function(a,b){
		return this.equalsExact(new Text().value(a),b);
		}
	this.equalsTextString=function(a,b){		
		return this.equalsExact(a,new Text().value(b));
		}		
	this.equalsNumberAmount=function(a,b){
		return this.equalsExact(new Amount().value(a),b);
		}	
	this.equalsAmountNumber=function(a,b){		
		return this.equals(a,new Amount().value(b));
		}		
		
		
		
		
		
		
		
		
		
	}
Toggle.prototype=new It();
function Calculation(firstItem,secondItem){
	this.lockFirst=false;
	this.lockSecond=false;
	this.first=new It().bind(firstItem);	
	this.first.calculation=this;
	this.first.afterChange=function(){
		if(this.calculation.lockFirst)return;
		this.calculation.lockFirst=true;		
		if(!this.calculation.lockSecond)this.calculation.second.value(this.calculation.calculateSecond());
		this.calculation.lockFirst=false;
		};	
	this.second=new It().bind(secondItem);
	this.second.calculation=this;		
	this.second.afterChange=function(){
		if(this.calculation.lockSecond)return;
		this.calculation.lockSecond=true;		
		if(!this.calculation.lockFirst)this.calculation.first.value(this.calculation.calculateFirst());
		this.calculation.lockSecond=false;
		};	
	this.calculateFirst=function(){return this.second.value();}
	this.calculateSecond=function(){return this.first.value();}		
	}
	